package com.gs.netty.support.handler.channel;

import com.gs.netty.core.common.CommandConstants;
import com.gs.netty.core.dispatch.Dispatch;


import com.gs.netty.support.properties.BaseNettyConfig;

import com.gs.netty.support.SocketProcessor;
import com.gs.netty.support.SynchronizedStack;
import com.gs.netty.support.dispatch.WebSocketDispatch;

import com.gs.netty.websocket.remoting.WebSocketInvocation;
import com.gs.netty.websocket.remoting.req.EventSocketRequest;
import com.gs.netty.websocket.remoting.req.SocketRequest;
import com.gs.netty.websocket.remoting.req.WebSocketRequest;
import com.gs.netty.websocket.remoting.resp.SocketResponse;
import com.gs.netty.websocket.remoting.resp.WebSocketResponse;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelPromise;
import io.netty.util.ReferenceCountUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.concurrent.ThreadPoolExecutor;

/**
 *
 * @param <P>
 */

public abstract class AbstractChannelDispatchHandler<P> extends
        AbstractChannelDuplexHandlerAdapter<WebSocketInvocation>
        implements Dispatch<WebSocketInvocation, ChannelHandlerContext> {


    protected final Logger log = LoggerFactory.getLogger(getClass());

    /**
     * 任务对象栈。作用任务对象的频发创建销毁，可以回收利用
     */
    private SynchronizedStack<P> processorCache;

    /**
     * 任务线程池
     */
    private ThreadPoolExecutor executor;

    /**
     * 指令程序分发器
     */
    private  Dispatch dispatch = new WebSocketDispatch();

    /**
     * 是否使用 指令程序分发器 来处理事件
     */
    private boolean useEventDispatch;



    public AbstractChannelDispatchHandler(BaseNettyConfig baseNettyConfig) {
        this.useEventDispatch = baseNettyConfig.isUseEventDispatch();

        if (useEventDispatch) {
            executor = baseNettyConfig.createThreadPoolExecutor();
        }
        this.processorCache = new SynchronizedStack<>(baseNettyConfig.getProcessorCacheInit(),
                baseNettyConfig.getProcessorCacheSize());
    }

    public boolean isUseEventDispatch() {
        return useEventDispatch;
    }

    public void setUseEventDispatch(boolean useEventDispatch) {
        this.useEventDispatch = useEventDispatch;
    }

    public Dispatch getDispatch() {
        return dispatch;
    }

    public void setDispatch(Dispatch dispatch) {
        this.dispatch = dispatch;
    }

    public AbstractChannelDispatchHandler() {
        this.processorCache = new SynchronizedStack<>();
    }

    public ThreadPoolExecutor getExecutor() {
        return executor;
    }

    public SynchronizedStack<P> getProcessorCache() {
        return processorCache;
    }

    public void setProcessorCache(SynchronizedStack<P> processorCache) {
        this.processorCache = processorCache;
    }

    public void setExecutor(ThreadPoolExecutor executor) {
        this.executor = executor;
    }

    protected WebSocketProcessor createSocketProcessor(WebSocketInvocation webSocketInvocation, ChannelHandlerContext ctx) {
        return new WebSocketProcessor(webSocketInvocation, ctx);
    }
    /**
     * 请求分发
     * @param webSocketInvocation
     * @param ctx
     */
    @Override
    public void dispatch(WebSocketInvocation webSocketInvocation, ChannelHandlerContext ctx) {

            WebSocketProcessor sc = null;
            if (getProcessorCache() != null) {
                sc = (WebSocketProcessor) getProcessorCache().pop();
            }
            if (sc == null) {
                // 创建处理任务
                sc = createSocketProcessor(webSocketInvocation, ctx);
            } else {
                sc.reset(webSocketInvocation, ctx);
            }

            if (getExecutor() != null) {
                // 执行
                getExecutor().execute(sc);
            }else {
                sc.run();
            }
    }



    /**
     * 用户事件
     * @param ctx
     * @param evt
     * @throws Exception
     */

    @Override
    public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {
        // 判断是否把事件交给 Dispatch 处理
        if (isUseEventDispatch()) {


            EventSocketRequest request = new EventSocketRequest(CommandConstants.USER_EVENT,evt);

            WebSocketResponse webSocketResponse = new WebSocketResponse(ctx);
//            dispatch(request,webSocketResponse);
        }else {
            // 默认处理逻辑
            log.warn("User event triggered but no custom handler found for event: {}", evt);
            super.userEventTriggered(ctx, evt);
        }
    }

    /**
     * 异常事件
     * @param ctx
     * @param cause
     * @throws Exception
     */
    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        if (isUseEventDispatch()) {
            EventSocketRequest request = new EventSocketRequest(CommandConstants.USER_EVENT,cause);
            WebSocketResponse webSocketResponse = new WebSocketResponse(ctx);
//            dispatch(request,webSocketResponse);
        }else {
            // 默认处理逻辑
            log.error("Exception caught but no custom handler found: {}", cause.getMessage(), cause);
            super.exceptionCaught(ctx, cause);
        }
    }

    public void setCorePoolSize(int corePoolSize){
        if (getExecutor()!=null) {
            getExecutor().setCorePoolSize(corePoolSize);
            getExecutor().setMaximumPoolSize(corePoolSize);
        }
    }

    public void setMaximumPoolSize(int maximumPoolSize){
        if (getExecutor()!=null) {
            getExecutor().setMaximumPoolSize(maximumPoolSize);
        }
    }

    /**
     * CHANNEL 关闭事件
     * @param ctx
     * @throws Exception
     */
    @Override
    public void channelInactive(ChannelHandlerContext ctx) throws Exception {
        if (isUseEventDispatch()) {
            EventSocketRequest request = new EventSocketRequest(CommandConstants.CHANNEL_INACTIVE,null);
            WebSocketResponse webSocketResponse = new WebSocketResponse(ctx);
//            dispatch(request,webSocketResponse);
        }else {
            super.channelInactive(ctx);
        }
    }

    /**
     * CHANNEL 激活事件
     * @param ctx
     * @throws Exception
     */
    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {
        if (isUseEventDispatch()) {

            EventSocketRequest request = new EventSocketRequest(CommandConstants.CHANNEL_ACTIVE,null);
            WebSocketResponse webSocketResponse = new WebSocketResponse(ctx);
//            dispatch(request,webSocketResponse);
        }else {
            super.channelActive(ctx);
        }
    }


    /**
     * 请求处理任务对象
     */
   public class WebSocketProcessor extends SocketProcessor {

       private int weight;

        public WebSocketProcessor(WebSocketInvocation webSocketInvocation ,ChannelHandlerContext ctx) {
            super(webSocketInvocation, ctx);
        }

        @Override
        protected void doRun() {
            try {
                SocketRequest request =new WebSocketRequest(getRequest());
                SocketResponse response= new SocketResponse(getResponse());
                AbstractChannelDispatchHandler.this.dispatch.dispatch(request,response);
            }catch (Throwable throwable){
                throwable.printStackTrace();
            }
            finally {
                response = null;
                request = null;
                //return to cache
                if (processorCache != null) {
                    // 添加对象
                    processorCache.push((P) this);
                }

            }

        }

    }

}
